<?php

namespace App\System\Http;

use App\System\Http\Message\ServerRequest;
use App\System\Http\Message\Stream;
use App\System\Http\Message\UploadFile;
use App\System\Http\Message\Uri;
use App\System\Http\Message\Utility;

class Request extends ServerRequest {
	private $request;
	private $header = [ ];
	function __construct() {
		$this->initHeaders ();
		
		$body = new Stream ( $this->getRowData () );
		$uri = $this->initUri ();
		$files = $this->initFiles ();
		$server = $this->initServer();
		$method = $_SERVER ['REQUEST_METHOD'];
		parent::__construct ( $method, $uri, null, $body, $_SERVER ["SERVER_PROTOCOL"], $server );
		$d = $this->withCookieParams ( $this->initCookie () );
		$d = $d->withQueryParams ( $this->initGet () );
		$d = $d->withParsedBody ( $this->initPost () );
		$d = $d->withUploadedFiles ( $files );
	}
	private function getRowData() {
		$rawData = file_get_contents ( 'php://input' );
		if (empty ( $rawData )) {
			if (isset ( $GLOBALS ['HTTP_RAW_POST_DATA'] )) {
				$rawData = $GLOBALS ['HTTP_RAW_POST_DATA'];
			}
		}
		if (empty ( $rawData )) {
			return "";
		}
		return $rawData;
	}
	function getRequestParam(...$key) {
		$data = array_merge ( $this->getParsedBody (), $this->getQueryParams () );
		;
		if (empty ( $key )) {
			return $data;
		} else {
			$res = [ ];
			foreach ( $key as $item ) {
				$res [$item] = isset ( $data [$item] ) ? $data [$item] : null;
			}
			if (count ( $key ) == 1) {
				return array_shift ( $res );
			} else {
				return $res;
			}
		}
	}
	function getRequest() {
		return isset ( $_REQUEST ) ? $_REQUEST : array ();
	}
	private function initUri() {
		$http = (isset ( $_SERVER ['HTTPS'] ) && $_SERVER ['HTTPS'] != 'off') ? 'https://' : 'http://';
		$url = $http . $_SERVER ['HTTP_HOST'] . $_SERVER ['PHP_SELF'];
		if ($_SERVER ['QUERY_STRING'] !== "" && ! empty ( $_SERVER ['QUERY_STRING'] )) {
			$url .= '?' . $_SERVER ['QUERY_STRING'];
		}
		$info = parse_url ( $url );
		$uri = new Uri ();
		$uri->withScheme ( $info ['scheme'] );
		
		if (! isset ( $info ['path'] )) {
			$info ['path'] = '/';
		}
		if (! isset ( $info ['port'] )) {
			if ('https' === $info ['scheme']) {
				$info ['port'] = 443;
			} else {
				$info ['port'] = 80;
			}
		}
		$uri->withPath ( $info ['path'] );
		
		$query = isset ( $info ['query'] ) ? $info ['query'] : '';
		
		$uri->withQuery ( $query );
		// host与port以header为准，防止经过proxy
		if (isset ( $info ['host'] )) {
			$host = $info ['host'];
			$host = explode ( ":", $host );
			$realHost = $host [0];
			$port = $info ['port'];
		} else {
			$realHost = '127.0.0.1';
			$port = $info ['port'];
		}
		$uri->withHost ( $realHost );
		$uri->withPort ( $port );
		$f1 = (isset ( $info ['user'] ) && ! empty ( $info ['user'] ));
		$f2 = (isset ( $info ['user'] ) && ! empty ( $info ['user'] ));
		if ($f1 && $f2) {
			$uri->withUserInfo ( $info ['user'], $info ['pass'] );
		}
		return $uri;
	}
	private function initHeaders() {
		$headers = array ();
		
		foreach ( $_SERVER as $name => $value ) {
			if (substr ( $name, 0, 5 ) == 'HTTP_') {
				$headers [str_replace ( ' ', '-', ucwords ( strtolower ( str_replace ( '_', ' ', substr ( $name, 5 ) ) ) ) )] = $value;
			}
		}
		if (isset ( $_SERVER ['PHP_AUTH_DIGEST'] )) {
			$headers ['AUTHORIZATION'] = $_SERVER ['PHP_AUTH_DIGEST'];
		} elseif (isset ( $_SERVER ['PHP_AUTH_USER'] ) && isset ( $_SERVER ['PHP_AUTH_PW'] )) {
			$headers ['AUTHORIZATION'] = base64_encode ( $_SERVER ['PHP_AUTH_USER'] . ':' . $_SERVER ['PHP_AUTH_PW'] );
		}
		if (isset ( $_SERVER ['CONTENT_LENGTH'] )) {
			$headers ['CONTENT-LENGTH'] = $_SERVER ['CONTENT_LENGTH'];
		}
		if (isset ( $_SERVER ['CONTENT_TYPE'] )) {
			$headers ['CONTENT-TYPE'] = $_SERVER ['CONTENT_TYPE'];
		}
		
		foreach ( $headers as $header => $val ) {
			$this->withAddedHeader ( strtolower ( $header ), $val );
		}
	}
	private function initFiles() {
		if (isset ( $_FILES )) {
			$normalized = array ();
			foreach ( $_FILES as $key => $value ) {
				$normalized [$key] = new UploadFile ( $value ['tmp_name'], ( int ) $value ['size'], ( int ) $value ['error'], $value ['name'], $value ['type'] );
			}
			return $normalized;
		} else {
			return array ();
		}
	}
	private function initCookie() {
		return isset ( $_COOKIE ) ? $_COOKIE : array ();
	}
	private function initPost() {
		return isset ( $_POST ) ? $_POST : array ();
	}
	private function initGet() {
		return isset ( $_GET ) ? $_GET : array ();
	}
	private function initServer() {
		return isset ( $_SERVER ) ? $_SERVER : array ();
	}
	final public function __toString(): string {
		// TODO: Implement __toString() method.
		return Utility::toString ( $this );
	}
}